package com.gyg.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 原生（Spring）异步线程池装配类
 * 实现AsyncConfigurer接口，重写其中的getAsyncExecutor()方法和getAsyncUncaughtExceptionHandler()方法
 * 这样在使用默认线程池的时候就会使用重写之后的线程池
 */
@Slf4j
@EnableAsync
@Configuration
public class NativeAsyncScheduledTaskConfig implements AsyncConfigurer {

    @Autowired
    private TaskThreadPoolConfig config;

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        //设置核心线程数量
        pool.setCorePoolSize(config.getCorePoolSize());
        //设置最大线程数量
        pool.setMaxPoolSize(config.getMaxPoolSize());
        //设置阻塞队列容量
        pool.setQueueCapacity(config.getQueueCapacity());
        //设置空闲线程保持连接的时间
        pool.setKeepAliveSeconds(config.getKeepAliveTime());
        //设置线程池名称前缀
        pool.setThreadNamePrefix("SpringDefaultThread-");
        //设置线程池关闭的时候等待所有任务都结束再关闭其他的bean
        pool.setWaitForTasksToCompleteOnShutdown(true);
        //设置线程池中任务的等待时间，如果在该时间内任务没有被销毁则强制销毁，以确保任务最后都能够关闭而不是阻塞
        pool.setAwaitTerminationSeconds(config.getAwaitTerminationSeconds());

        /**
         * 设置线程池的拒绝策略
         *  CallerRunsPolicy()：交由调用方线程运行，比如 main 线程。
         *  AbortPolicy()：直接抛出异常。
         *  DiscardPolicy()：直接丢弃。
         *  DiscardOldestPolicy()：丢弃队列中最老的任务。
         * */
        pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        pool.initialize();
        log.info("Spring ThreadPool Config Success------------");
        return pool;
    }

    /**
     * 异步任务未捕获异常处理
     *
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (es, method, params) -> {
            log.info(es.getMessage());
            log.info(method.getName());
        };
    }
}
